﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Messaging;
using System.Threading;
using System.Threading.Tasks;
using System.Reflection;
using PipeClient;

namespace LogWriter
{
    class Program
    {
        private static MessageQueue mq = null;

        private static object LockState = new object();
     
        static void Main(string[] args)
        {
            if (args.Length > 0)
            {
                string arg = args[0];
                if (!string.IsNullOrEmpty(arg))
                {
                    ParentFormHandle = (IntPtr)Int32.Parse(arg);
                }
            }
            Console.WriteLine("MSMQ_ReceiveLogAsync start...");
            try
            {
                mq = new MessageQueue(@".\Private$\myQueue");
                mq.ReceiveCompleted += new ReceiveCompletedEventHandler(MessageReceived);
                mq.BeginReceive(MessageQueue.InfiniteTimeout);
                OnAppStartupFinished();               
            }
            catch (Exception ex)
            {
                OnAppStartupFinished(0, ex.Message);
                Console.WriteLine(ex.ToString());
            }
            Console.ReadLine();
        }

        private static void MessageReceived(object source, ReceiveCompletedEventArgs asyncResult)
        {
            bool isReceivedSucceed = true;
            MessageQueue mq = null;
            try
            {
                //Connect to the queue
                mq = (MessageQueue)source;
                System.Messaging.Message m = mq.EndReceive(asyncResult.AsyncResult);
                m.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(LogInfo) });
                ThreadPool.QueueUserWorkItem(new WaitCallback(InvokeWriteLog), m.Body);
            }
            catch (MessageQueueException)
            {
                isReceivedSucceed = false;
            }
            catch (Exception ex)
            {
                isReceivedSucceed = false;
                Console.WriteLine(ex.Message);
            }
            finally
            {
                if (isReceivedSucceed)
                {
                    mq.BeginReceive(MessageQueue.InfiniteTimeout);
                }
            }
        }

        private static void InvokeWriteLog(object obj)
        {
            LogInfo info = obj as LogInfo;
            if (info != null && !info.IsEmpty())
            {
                WriteLine(info);
            }          
        }

        /// <summary>
        /// 将一行信息写入日记文件
        /// </summary>
        /// <param name="info">日记文件信息</param>
        private static void WriteLine(LogInfo info)
        {
            lock (LockState)
            {
                using (FileStream fs = new FileStream(info.LogFullName, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    using (StreamWriter m_streamWriter = new StreamWriter(fs))
                    {
                        m_streamWriter.BaseStream.Seek(0, SeekOrigin.End);
                        m_streamWriter.WriteLine(info.Content);
                        m_streamWriter.Flush();
                        m_streamWriter.Close();
                    }
                    fs.Close();
                }
            }         
        }

        protected static IntPtr ParentFormHandle = IntPtr.Zero;

        /// <summary>
        /// 指示是否已经通知主窗体加载完成
        /// </summary>
        protected static bool _bNotified = false;

        public static string AppName = Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase);

        /// <summary>
        /// 通知主窗体该进程启动已经完成
        /// </summary>
        protected static void OnAppStartupFinished(int code = 1, string msg = "程序加载成功")
        {
            // 当父窗体为空时，不需要通知
            if (IntPtr.Zero == ParentFormHandle || _bNotified)
            {
                Console.WriteLine(string.Format("{0}获取父进程主窗口句柄为空，不启用进程监测.", AppName));
                return;
            }
            string sendMsg = string.Format("{0}#{1}#{2}", AppName, code, msg);
            Pipe t = new Pipe(11, sendMsg, "MainStartup");
            Task.Factory.StartNew(new Action(t.run));
            Console.WriteLine("已经通知主窗体启动完成: " + AppName);
            _bNotified = true;
        }

    }
}
